package cn.hbads.support.json;

import cn.hbads.support.error.CommonErrorType;
import cn.hbads.support.error.ErrorType;
import cn.hbads.support.json.support.JacksonConfigSupport;
import cn.hbads.support.log.LogUtil;
import cn.hbads.support.structure.result.ComputeResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <b>Json序列化/反序列化工具类</b>
 *
 * @author yvvb
 * @className JsonUtil
 * @date 2025/4/17 13:31
 **/
public final class JsonUtil {
    public static final String GENERIC_NAMESPACE = "generic";
    private static final ObjectMapper configObjectMapper;
    private static final Map<String, JsonMethodExecutor> executorMap = new ConcurrentHashMap<>();

    static {
        configObjectMapper = JacksonConfigSupport.createConfigObjectMapper();
    }


    private JsonUtil() {
    }

    /*----默认的序列化器方法实现-----*/
    public static ComputeResult<String, ErrorType> toJson(Object object) {
        return toJson(configObjectMapper, object);
    }

    public static <T> ComputeResult<T, ErrorType> parseJson(String jsonStr, Class<T> targetClazz) {
        return parseJson(configObjectMapper, jsonStr, targetClazz);
    }

    public static <T> ComputeResult<T, ErrorType> parseJson(String jsonStr, TypeReference<T> typeReference) {
        return parseJson(configObjectMapper, jsonStr, typeReference);
    }

    public static <E> ComputeResult<ArrayList<E>, ErrorType> parseJsonToList(String jsonStr, Class<E> elementClass) {
        return parseJsonToList(configObjectMapper, jsonStr, elementClass);
    }

    public static <K, V> ComputeResult<LinkedHashMap<K, V>, ErrorType> parseJsonToMap(String jsonStr, Class<K> keyClass, Class<V> valueClass) {
        return parseJsonToMap(configObjectMapper, jsonStr, keyClass, valueClass);
    }

    public static ComputeResult<JsonNode, ErrorType> readToJsonNode(Object obj) {
        return readToJsonNode(configObjectMapper, obj);
    }

    public static JsonMethodExecutor use(String namespace) {
        return executorMap.get(namespace);
    }

    public static JsonMethodExecutor useGeneric() {
        return executorMap.putIfAbsent(GENERIC_NAMESPACE, new JsonMethodExecutor(JacksonConfigSupport.createGenericObjectMapper()));
    }

    public static JsonMethodExecutor useWithPutGenericIfAbsent(String namespace) {
        return executorMap.putIfAbsent(namespace, new JsonMethodExecutor(JacksonConfigSupport.createGenericObjectMapper()));
    }

    public static boolean put(String namespace, ObjectMapper objectMapper) {
        if (StringUtils.isBlank(namespace) || Objects.isNull(objectMapper)) {
            return false;
        } else {
            executorMap.put(namespace, new JsonMethodExecutor(objectMapper));
            return true;
        }
    }

    /*----内部private实现----*/
    private static ComputeResult<String, ErrorType> toJson(ObjectMapper objectMapper, Object object) {
        try {
            return ComputeResult.success(objectMapper.writeValueAsString(object));
        } catch (JsonProcessingException exception) {
            LogUtil.error(exception, "Convert object to json failed!\nObject: {}", object.toString());
            return ComputeResult.fail(CommonErrorType.JSON_SERIALIZE_ERROR);
        }
    }

    private static <T> ComputeResult<T, ErrorType> parseJson(ObjectMapper objectMapper, String jsonStr, Class<T> targetClazz) {
        try {
            return ComputeResult.success(objectMapper.readValue(jsonStr, targetClazz));
        } catch (JsonProcessingException exception) {
            LogUtil.error("Parse json failed! \nJsonStr:{}\nTargetClass: {}", jsonStr, targetClazz.getName());
            return ComputeResult.fail(CommonErrorType.JSON_DESERIALIZE_ERROR, exception);
        }
    }

    private static <T> ComputeResult<T, ErrorType> parseJson(ObjectMapper objectMapper, String jsonStr, TypeReference<T> typeReference) {
        try {
            return ComputeResult.success(objectMapper.readValue(jsonStr, typeReference));
        } catch (JsonProcessingException exception) {
            LogUtil.error("Parse json failed! \nJsonStr:{}\nTypeName: {}", jsonStr, typeReference.getType().getTypeName());
            return ComputeResult.fail(CommonErrorType.JSON_DESERIALIZE_ERROR, exception);
        }
    }

    private static <E> ComputeResult<ArrayList<E>, ErrorType> parseJsonToList(ObjectMapper objectMapper, String jsonStr, Class<E> elementClass) {
        return parseJson(objectMapper, jsonStr, new TypeReference<ArrayList<E>>() {
            @Override
            public Type getType() {
                return objectMapper.getTypeFactory()
                        .constructCollectionType(ArrayList.class, elementClass);
            }
        });
    }

    private static <K, V> ComputeResult<LinkedHashMap<K, V>, ErrorType> parseJsonToMap(ObjectMapper objectMapper, String jsonStr, Class<K> keyClass, Class<V> valueClass) {
        return parseJson(objectMapper, jsonStr, new TypeReference<LinkedHashMap<K, V>>() {
            @Override
            public Type getType() {
                return objectMapper.getTypeFactory()
                        .constructMapType(LinkedHashMap.class, keyClass, valueClass);
            }
        });
    }

    private static ComputeResult<JsonNode, ErrorType> readToJsonNode(ObjectMapper objectMapper, Object obj) {
        try {
            return ComputeResult.success(objectMapper.readTree(objectMapper.writeValueAsString(obj)));
        } catch (JsonProcessingException exception) {
            LogUtil.error(exception, "Convert object to json failed!\nObject: {}", obj.toString());
            return ComputeResult.fail(CommonErrorType.JSON_NODE_TRANSFER_ERROR, exception);
        }
    }

    /*---添加/切换其他的序列化器-----*/
    public static class JsonMethodExecutor {
        private final ObjectMapper objectMapper;

        public JsonMethodExecutor(ObjectMapper objectMapper) {
            this.objectMapper = objectMapper;
        }

        public ComputeResult<String, ErrorType> toJson(Object object) {
            return JsonUtil.toJson(objectMapper, object);
        }

        public <T> ComputeResult<T, ErrorType> parseJson(String jsonStr, Class<T> targetClazz) {
            return JsonUtil.parseJson(objectMapper, jsonStr, targetClazz);
        }

        public <T> ComputeResult<T, ErrorType> parseJson(String jsonStr, TypeReference<T> typeReference) {
            return JsonUtil.parseJson(objectMapper, jsonStr, typeReference);
        }

        public <E> ComputeResult<ArrayList<E>, ErrorType> parseJsonToList(String jsonStr, Class<E> elementClass) {
            return JsonUtil.parseJsonToList(objectMapper, jsonStr, elementClass);
        }

        public <K, V> ComputeResult<LinkedHashMap<K, V>, ErrorType> parseJsonToMap(String jsonStr, Class<K> keyClass, Class<V> valueClass) {
            return JsonUtil.parseJsonToMap(objectMapper, jsonStr, keyClass, valueClass);
        }

        public ComputeResult<JsonNode, ErrorType> readToJsonNode(Object obj) {
            return JsonUtil.readToJsonNode(objectMapper, obj);
        }
    }
}
